<?php

namespace longhu\library;

use longhu\library\redis\HasTrait;
use longhu\library\redis\Instruct;
use longhu\library\redis\RString;
use longhu\library\redis\UnorderedSet;
use longhu\library\redis\ZetTrait;

class RedisCommand
{
    use HasTrait,ZetTrait,Instruct,RString,UnorderedSet;
    protected $redis;

    public function __construct($redis)
    {
        $this->redis = $redis;
    }


    /**
     * 选择数据库
     * @param int $dbId 数据库ID号
     * @return bool
     */
    public function select($dbId)
    {
        $this->dbId = $dbId;
        return $this->redis->select($dbId);
    }

    /**
     * 清空当前数据库
     * @return bool
     */
    public function flushDB()
    {
        return $this->redis->flushDB();
    }

    /**
     * info 返回当前库状态
     * @return string
     */
    public function info()
    {
        return $this->redis->info();
    }

    /**
     * 同步保存数据到磁盘
     */
    public function save()
    {
        return $this->redis->save();
    }

    /**
     * 异步保存数据到磁盘
     */
    public function bgSave()
    {
        return $this->redis->bgSave();
    }

    /**
     * 返回最后保存到磁盘的时间
     */
    public function lastSave()
    {
        return $this->redis->lastSave();
    }

    /**
     * 返回key,支持*多个字符，?一个字符
     * 只有*　表示全部
     * @param string $key
     * @return array
     */
    public function keys($key)
    {
        return $this->redis->keys($key);
    }

    /**
     * del 删除指定key
     * @param $key
     * @return mixed
     */
    public function del($key)
    {
        return $this->redis->del($key);
    }

    /**
     * exists 判断一个key值是不是存在
     * Created by PhpStorm.
     * User: w
     * Date: 2018-12-09
     * Time: 12:07
     * @param $key
     * @return mixed
     */
    public function exists($key)
    {
        return $this->redis->exists($key);
    }

    /**
     * expire 为一个key设定过期时间 单位为秒
     * @param $key
     * @param $expire
     * @return mixed
     */
    public function expire($key,$expire)
    {
        return $this->redis->expire($key,$expire);
    }

    /**
     * ttl 返回一个key还有多久过期，单位秒
     * @param $key
     * @return mixed
     */
    public function ttl($key)
    {
        return $this->redis->ttl($key);
    }

    /**
     * expireAt 设定一个key什么时候过期，time为一个时间戳
     * Created by PhpStorm.
     * User: w
     * Date: 2018-12-09
     * Time: 12:06
     * @param $key
     * @param $time
     * @return mixed
     */
    public function expireAt($key,$time)
    {
        return $this->redis->expireAt($key,$time);
    }

    /**
     * 关闭服务器链接
     */
    public function close()
    {
        return $this->redis->close();
    }

    /**
     * 关闭所有连接
     */
    public static function closeAll()
    {
        foreach(static::$_instance as $o)
        {
            if($o instanceof self)
                $o->close();
        }
    }

    /** 这里不关闭连接，因为session写入会在所有对象销毁之后。
    public function __destruct()
    {
    return $this->redis->close();
    }
     **/
    /**
     * 返回当前数据库key数量
     */
    public function dbSize()
    {
        return $this->redis->dbSize();
    }

    /**
     * 返回一个随机key
     */
    public function randomKey()
    {
        return $this->redis->randomKey();
    }

    /**
     * 得到当前数据库ID
     * @return int
     */
    public function getDbId()
    {
        return $this->dbId;
    }

    /**
     * 返回当前密码
     */
    public function getAuth()
    {
        return $this->auth;
    }

    public function getHost()
    {
        return $this->host;
    }

    public function getPort()
    {
        return $this->port;
    }

    public function getConnInfo()
    {
        return [
            'host' => $this->host,
            'port' => $this->port,
            'auth' => $this->auth
        ];
    }

    /**
     * watch 监控key,就是一个或多个key添加一个乐观锁
     * 在此期间如果key的值如果发生的改变，刚不能为key设定值
     * 可以重新取得Key的值。
     * @param $key
     * @return mixed
     */
    public function watch($key)
    {
        return $this->redis->watch($key);
    }

    /**
     * 取消当前链接对所有key的watch
     *  EXEC 命令或 DISCARD 命令先被执行了的话，那么就不需要再执行 UNWATCH 了
     */
    public function unwatch()
    {
        return $this->redis->unwatch();
    }

    /**
     * multi 开启一个事务
     * 事务的调用有两种模式Redis::MULTI和Redis::PIPELINE，
     * 默认是Redis::MULTI 模式，
     * Redis::PIPELINE管道模式速度更快，但没有任何保证原子性有可能造成数据的丢失
     * @param $type
     * @return mixed
     */
    public function multi($type = \Redis::MULTI)
    {
        return $this->redis->multi($type);
    }

    /**
     * 执行一个事务
     * 收到 EXEC 命令后进入事务执行，事务中任意命令执行失败，其余的命令依然被执行
     */
    public function exec()
    {
        return $this->redis->exec();
    }

    /**
     * 回滚一个事务
     */
    public function discard()
    {
        return $this->redis->discard();
    }

    /**
     * 测试当前链接是不是已经失效
     * 没有失效返回+PONG
     * 失效返回false
     */
    public function ping()
    {
        return $this->redis->ping();
    }

    public function auth($auth)
    {
        return $this->redis->auth($auth);
    }

    /*********************自定义的方法,用于简化操作************************/

    /**
     * hashAll 得到一组的ID号
     * @param $prefix
     * @param $ids
     * @return array|bool
     */
    public function hashAll($prefix,$ids)
    {
        if($ids == false)
            return false;

        if( is_string($ids) )
            $ids = explode(',', $ids);

        $arr = [];
        foreach($ids as $id) {
            $key = $prefix.'.'.$id;
            $res = $this->hGetAll($key);
            if($res != false)
                $arr[] = $res;
        }

        return $arr;
    }

    /**
     * pushMessage 生成一条消息，放在redis数据库中。使用0号库。
     * @param $lkey
     * @param string|array $msg
     * @return string
     */
    public function pushMessage($lkey, $msg)
    {
        if(is_array($msg))
            $msg = json_encode($msg);

        $key = md5($msg);

        //如果消息已经存在，删除旧消息，已当前消息为准
        //echo $n=$this->lRem($lkey, 0, $key)."\n";
        //重新设置新消息
        $this->lPush($lkey, $key);
        $this->setex($key, 3600, $msg);
        return $key;
    }

    /**
     * delKeys 得到条批量删除key的命令
     * @param $keys
     * @param $dbId
     * @return string
     */
    public function delKeys($keys,$dbId)
    {
        $redisInfo = $this->getConnInfo();
        $cmdArr = [
            'redis-cli',
            '-a',
            $redisInfo['auth'],
            '-h',
            $redisInfo['host'],
            '-p',
            $redisInfo['port'],
            '-n',
            $dbId,
        ];
        $redisStr = implode(' ', $cmdArr);
        $cmd = "{$redisStr} KEYS \"{$keys}\" | xargs {$redisStr} del";
        return $cmd;
    }


}